package drds.plus.repository.mysql.function;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import drds.plus.sql_process.abstract_syntax_tree.expression.item.function.Function;
import drds.tools.$;
import drds.tools.ClassSearcher;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;

@Slf4j
public class FunctionStringConstructorManager {
    private static Map<String, Class<?>> functionCaches = Maps.newConcurrentMap();

    static {
        initFunctions();
    }

    /**
     * 查找对应名字的函数类，忽略大小写
     *
     * @param functionName
     * @return
     */
    public static FunctionStringConstructor getExtraFunction(String functionName) {
        String name = functionName;
        Class clazz = functionCaches.get(name);
        FunctionStringConstructor result = null;

        if (clazz == null) {
            return null;
        }

        if (clazz != null) {
            try {
                result = (FunctionStringConstructor) clazz.newInstance();
            } catch (Exception e) {
                throw new RuntimeException("init function failed", e);
            }
        }

        if (result == null) {
            throw new RuntimeException("not found FunctionImpl : " + functionName);
        }

        return result;
    }

    public static void addFuncion(Class clazz) {

        try {
            FunctionStringConstructor sample = (FunctionStringConstructor) clazz.newInstance();

            String[] names = sample.getFunctionNames();

            for (String name : names) {
                Class oldClazz = functionCaches.put(name.toUpperCase(), clazz);
                if (oldClazz != null) {
                    log.warn(" rightCursorNextDuplicateValueRowData function :" + name + ", old class : " + oldClazz.getName());
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("init function failed", e);
        }

    }

    private static void initFunctions() {
        List<Class> classes = Lists.newArrayList();
        classes.addAll(ClassSearcher.findSubClass(FunctionStringConstructor.class, $.rootPackageName));
        for (Class clazz : classes) {
            addFuncion(clazz);
        }
    }

    public FunctionStringConstructor getConstructor(Function func) {
        return getExtraFunction(func.getFunctionName());
    }

}
